package com.open4cn.simulator.device.datacolor;

import com.open4cn.simulator.connect.tcp.TCPServerConnector;
import com.open4cn.simulator.connect.tcp.handler.DispatcherHandler;
import com.open4cn.simulator.connect.tcp.handler.ReadBlockHandler;
import com.open4cn.simulator.connect.tcp.handler.ReadLogHandler;
import com.open4cn.simulator.connect.tcp.handler.WriteLogHandler;
import com.open4cn.simulator.connect.tcp.listenner.ConnectStatusFutureListener;
import com.open4cn.simulator.core.connector.ConnectAddress;
import com.open4cn.simulator.core.connector.IConnector;
import com.open4cn.simulator.core.device.DeviceInfo;
import com.open4cn.simulator.core.device.DeviceParameters;
import com.open4cn.simulator.core.device.DeviceStatus;
import com.open4cn.simulator.core.device.IDevice;
import com.open4cn.simulator.core.device.IDeviceFactory;
import com.open4cn.simulator.core.ext.DataColorStatus;
import com.open4cn.simulator.core.parser.IInstructionParser;
import com.open4cn.simulator.core.parser.InstructionParserChain;
import com.open4cn.simulator.device.AnswerManager;
import com.open4cn.simulator.device.DeviceStatusManager;
import com.open4cn.simulator.parser.Unknown;
import com.open4cn.simulator.parser.datacolor.dc1000.ZA$01$Pattern;
import com.open4cn.simulator.parser.datacolor.dc1000.ZB4RE0167;
import com.open4cn.simulator.parser.datacolor.dc1000.ZF0000130;
import com.open4cn.simulator.parser.datacolor.dc1000.ZF0010131;
import com.open4cn.simulator.parser.datacolor.dc1000.ZGE0126;
import com.open4cn.simulator.parser.datacolor.dc1000.ZGI012A;
import com.open4cn.simulator.parser.datacolor.dc1000.ZM$01$Pattern;
import com.open4cn.simulator.parser.datacolor.dc1000.ZM$GB01$Pattern;
import com.open4cn.simulator.parser.datacolor.dc1000.ZS010D;
import com.open4cn.simulator.parser.datacolor.dc1000.ZSX0145;
import com.open4cn.simulator.parser.datacolor.dc1000.ZW4RE017C;
import com.open4cn.simulator.parser.datacolor.dc1000.ZYGS016D;
import com.open4cn.simulator.protocol.datacolor.DataColorDecoder;
import com.open4cn.simulator.protocol.datacolor.DataColorEncoder;

import java.util.Arrays;
import java.util.List;

/**
 * @author yinxiaopeng
 * @version 1.0.0
 * @company 致景科技
 * @department 飞梭BU/研发
 * @description
 * @Email yinxiaopeng@zj.tech
 * @date 2022-04-30 16:38
 */
public class DataColor1000Factory implements IDeviceFactory {

    @Override
    public IDevice build(DeviceParameters parameters) {
        DataColor1000 dataColor1000 = new DataColor1000();
        dataColor1000.setDeviceInfo(deviceInfo(parameters));
        dataColor1000.setConnector(connector(dataColor1000.getDeviceInfo()));
        return dataColor1000;
    }


    private DeviceInfo<Object, DataColorStatus> deviceInfo(DeviceParameters parameters) {
        DeviceInfo<Object, DataColorStatus> deviceInfo = new DeviceInfo<>();
        deviceInfo.setId(parameters.getId());
        deviceInfo.setName(parameters.getName());
        deviceInfo.setBrand(parameters.getBrand());
        deviceInfo.setModel(parameters.getModel());
        deviceInfo.setDeviceStatus(deviceStatus(deviceInfo));
        deviceInfo.setConnectAddress(new ConnectAddress(parameters.getInteger(DCPredefinedAttributes.PORT)));
        return deviceInfo;
    }


    private DeviceStatus deviceStatus(DeviceInfo deviceInfo) {
        String deviceId = deviceInfo.getId();
        DeviceStatusManager deviceStatusManager = DeviceStatusManager.getInstance();
        DeviceStatus deviceStatus = deviceStatusManager.load(deviceId);
        if (null == deviceStatus) {
            deviceStatus = new DeviceStatus(deviceId, deviceInfo.getBrand(), deviceInfo.getModel(), new DataColorStatus());
        }
        deviceStatusManager.put(deviceId, deviceStatus);
        return deviceStatus;
    }


    private IConnector connector(DeviceInfo deviceInfo) {
        TCPServerConnector connector = new TCPServerConnector();
        connector.beforeDecod(new ReadLogHandler(deviceInfo.getName()));
        connector.beforeDecod(new ReadBlockHandler(deviceInfo.getDeviceStatus()));
        connector.decoder(DataColorDecoder.class);
        connector.afterDecod(new DispatcherHandler(chain(deviceInfo)));
        connector.encoder(DataColorEncoder.class);
        connector.afterEncod(new WriteLogHandler(deviceInfo.getName()));
        connector.addFutureListenner(new ConnectStatusFutureListener(connector.getConnectStatus()));
        return connector;
    }

    private InstructionParserChain chain(DeviceInfo deviceInfo) {
        DataColorStatus dataColorStatus = (DataColorStatus) deviceInfo.getDeviceStatus().getData();
        List<IInstructionParser> parsers = Arrays.asList(
                new ZS010D(dataColorStatus),
                new ZM$01$Pattern(dataColorStatus),
                new ZSX0145(dataColorStatus),
                new ZF0000130(dataColorStatus),
                new ZF0010131(dataColorStatus),
                new ZA$01$Pattern(dataColorStatus),
                new ZGE0126(dataColorStatus),
                new ZGI012A(dataColorStatus),
                new ZB4RE0167(dataColorStatus),
                new ZW4RE017C(dataColorStatus),
                new ZM$GB01$Pattern(dataColorStatus),
                new ZYGS016D(dataColorStatus),
                new Unknown()
        );
        manageAnswer(deviceInfo.getId(), parsers);
        return new InstructionParserChain(parsers);
    }

    private void manageAnswer(String deviceId, List<IInstructionParser> parsers) {
        AnswerManager answerManager = AnswerManager.getInstance();
        parsers.forEach(parser -> {
            answerManager.put(deviceId, parser.getAnswers());
        });
    }

}
